//
//  mb_SoundSystem.c
//  MBAudio
//
//  Created by avansc on 4/18/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include <stdlib.h>
#include <stdio.h>

#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <AL/alure.h>

#include "MBAudio.h"

#ifdef __cplusplus
extern "C" {
#endif
    extern mb_pUIMap_t *mb_init_pUIMap();
    extern uint32_t mb_get_pUIMap(mb_pUIMap_t *h, const char *key);
    extern uint32_t mb_put_pUIMap(mb_pUIMap_t *h, const char *key, int *ret);
#ifdef __cplusplus
}
#endif

static mb_SoundSystem_t *g_SoundSystem = NULL;

static int initSoundSystem();
static unsigned int* loadSoundFile(char *file);
static mb_SoundBuffer_t* addSoundBufferFromFile(char *name, char *file);
static mb_SoundBuffer_t* addSoundBufferFromMem(char *name, mb_SoundBuffer_t buffer);
static mb_SoundSource_t addSoundSource(char *name);
static int attachBufferToSource(char *buffer, char *source);
static int attach(mb_SoundBuffer_t* buffer, mb_SoundSource_t* source);
static void playSource(char *source);
static int createSource(char *source);
static mb_SoundSource_t getSource(char *source);




mb_SoundSource_t getSource(char *source)
{
    mb_SoundSource_t ret = { g_SoundSystem->m_sourceMap->get(source), 0};
    return ret;
}

void mb_playSource(mb_SoundSource_t *source)
{
    alSourcePlay(*source->m_source);
}

int mb_isPlaying(mb_SoundSource_t *source)
{
    int ret;
    alGetSourcei(*source->m_source, AL_SOURCE_STATE, &ret);
    return (ret == AL_PLAYING ? 1 : 0);
}

mb_SoundSystem_t *createSoundSystem(void)
{
    mb_SoundSystem_t *system = (mb_SoundSystem_t*)malloc(sizeof(mb_SoundSystem_t));
    
    system->m_initialized = 0;
    
    system->initSoundSystem = &initSoundSystem;
    system->loadSoundFile = &loadSoundFile;
    system->addSoundBufferFromFile = &addSoundBufferFromFile;
    system->addSoundSource = &addSoundSource;
    system->attachBufferToSource = &attachBufferToSource;
    system->playSource = &playSource;
    system->createSource = &createSource;
    system->getSource = &getSource;
    
    if(!g_SoundSystem)
    {
        setActiveSoundSystem(system);
        initSoundSystem();
    }
    
    return system;
}

mb_SoundSystem_t *setActiveSoundSystem(mb_SoundSystem_t *system)
{
    mb_SoundSystem_t *ret = g_SoundSystem;
    g_SoundSystem = system;
    return ret;
}

int initSoundSystem()
{
    if(g_SoundSystem->m_initialized == 1)
        return 0;
    
    g_SoundSystem->m_device = alcOpenDevice(NULL);
    
    if (g_SoundSystem->m_device) { 
        g_SoundSystem->m_context = alcCreateContext(g_SoundSystem->m_device,NULL); 
        alcMakeContextCurrent(g_SoundSystem->m_context);  
    }
    
    g_SoundSystem->m_bufferMap = createSoundBufferMap();
    setActiveSoundBufferMap(g_SoundSystem->m_bufferMap);
    g_SoundSystem->m_bufferMap->init();
    
    g_SoundSystem->m_sourceMap = createSoundSourceMap();
    setActiveSoundSourceMap(g_SoundSystem->m_sourceMap);
    g_SoundSystem->m_sourceMap->init();
    
    g_SoundSystem->m_listener = createSoundListener();
    setActiveSoundListener(g_SoundSystem->m_listener);
    g_SoundSystem->m_listener->init();
    
    g_SoundSystem->m_initialized = 1;
    
    return 1;
}

unsigned int* loadSoundFile(char *file)
{
    unsigned int *buf = mb_genBuffer(1);
    *buf = alureCreateBufferFromFile(file);
    
    if(!&buf)
    {
        printf("Could not load %s: %s\n", file, alureGetErrorString());
        return NULL;
    }
    
    return buf;
}

mb_SoundBuffer_t* addSoundBufferFromFile(char *name, char *file)
{
    mb_SoundBuffer_t *buf = loadSoundFile(file);
    g_SoundSystem->m_bufferMap->set(name, buf);
    return buf;
}

mb_SoundBuffer_t* addSoundBufferFromMem(char *name, mb_SoundBuffer_t buffer)
{
    //TODO
    return NULL;
}

mb_SoundSource_t addSoundSource(char *name)
{
    
    unsigned int* temp = mb_genSource(1);
    mb_SoundSource_t src = { temp, 0 };
    g_SoundSystem->m_sourceMap->set(name, temp);
    return src;
}

int attachBufferToSource(char *buffer, char *source)
{
    unsigned int *tempS = g_SoundSystem->m_sourceMap->get(source);
    unsigned int *tempB = g_SoundSystem->m_bufferMap->get(buffer);
    
    if(tempS == NULL || tempB == NULL)
    {
        if(tempS == NULL)
            printf("no such source\n");
        if(tempB == NULL)
            printf("no such buffer\n");
        
        return -1;
    }
    
    alSourcei(*tempS, AL_BUFFER, *tempB);
    return 1;
}

int attach(mb_SoundBuffer_t *buffer, mb_SoundSource_t *source)
{
    if(source->m_source == NULL || buffer == NULL)
    {
        if(source->m_source == NULL)
            printf("no such source\n");
        if(buffer == NULL)
            printf("no such buffer\n");
        
        return -1;
    }
    
    alSourcei(*source->m_source, AL_BUFFER, *buffer);
    return 1;
}

void playSource(char *source)
{
    unsigned int *temp = g_SoundSystem->m_sourceMap->get(source);
    if(temp)
        alSourcePlay(*temp);
}

int createSource(char *source)
{
    return 1;
}

unsigned int *mb_genSource(int num)
{
    unsigned int* src = (unsigned int*)malloc(sizeof(unsigned int)*num);
    alGenSources(num, src);
    return src;
}

unsigned int *mb_genBuffer(int num)
{
    unsigned int* src = (unsigned int*)malloc(sizeof(unsigned int)*num);
    alGenSources(num, src);
    return src;
}